package v1

import (
	"crypto/sha1"
	json2 "encoding/json"
	"fmt"
	"html/template"
	"math/rand"
	"net/http"
	"reflect"
	"runtime"
	"strings"
	"time"
	"unsafe"
)

var (
	Debug  = false
	Layout []string
)

type view struct {
	data map[string]interface{}

	w http.ResponseWriter
}
type json struct {
	w http.ResponseWriter
}

func (v *view) assign(name string, value interface{}) *view {
	v.data[name] = value
	return v
}
func (v *view) render(view_page ...string) {
	if len(view_page) > 0 {
		tp, err := template.ParseFiles(includeTemp("./view/"+view_page[0]+".html", Layout)...)
		if err != nil {
			thownErr(err, v.w)
			return
		}
		err = tp.Execute(v.w, v.data)
		thownErr(err, v.w)
		return
	}
	pc := make([]uintptr, 1)
	runtime.Callers(2, pc)
	s := getTemplatePath(runtime.FuncForPC(pc[0]).Name())
	tp, err := template.ParseFiles(includeTemp(s, Layout)...)
	if err != nil {
		thownErr(err, v.w)
		return
	}
	err = tp.Execute(v.w, v.data)
	thownErr(err, v.w)
}

func View(w http.ResponseWriter) *view {
	return &view{
		data: make(map[string]interface{}),
		w:    w,
	}
}
func Json(w http.ResponseWriter) *json {
	return &json{
		w: w,
	}
}
func byt(s string) []byte {
	rs := *(*reflect.StringHeader)(unsafe.Pointer(&s))
	return *(*[]byte)(unsafe.Pointer(&rs))
}
func str(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}
func thownErr(err error, w http.ResponseWriter) {
	if err == nil {
		return
	}
	if Debug {
		w.Write(byt(err.Error()))
	} else {
		http.NotFound(w, nil)
		// w.WriteHeader(404)
		// w.Write(byt("404 NOT FOUND"))
	}
}

// 提取模板路径
func getTemplatePath(s string) string {
	sr := strings.Split(s, ".")
	p := 0
	out := "./view"
	for k, v := range sr[1][1:] {
		if v > 64 && v < 91 {
			if p == 0 {
				if sr[1][p:k+1] != "Page" {
					return ""
				}
				p = k + 1
			}
			out += strings.ToLower(sr[1][p:k+1]) + "/"
			p = k + 1
		}
	}
	out += strings.ToLower(sr[1][p:]) + ".html"
	return out
}
func SetDebug() {
	Debug = true
}
func includeTemp(s string, ss []string) []string {
	if len(ss) == 0 {
		return []string{s}
	}
	n := make([]string, 0)
	n = append(n, s)
	n = append(n, ss...)
	return n
}

func (j *json) Success(data interface{}) {
	b, err := json2.Marshal(data)
	if err != nil {
		thownErr(err, j.w)
		return
	}
	j.w.Header().Set("content-type", "application/json")
	j.w.Write(b)
}
func (j *json) Error(err string) {
	j.w.WriteHeader(503)
	j.w.Header().Set("content-type", "application/json")
	j.w.Write(byt(`{"msg":"` + err + `"}`))
}
func CreateUUID(xtr []byte) []byte {
	str := fmt.Sprintf("%x", xtr)
	strLow := ComplementHex(str[:(len(str)-1)/3], 8)
	strMid := ComplementHex(str[(len(str)-1)/3:(len(str)-1)*2/3], 4)
	<-time.After(1 * time.Nanosecond)
	ti := time.Now().UnixNano()
	return []byte(fmt.Sprintf("%s-%x-%s-%s", strLow, ti, strMid, ""))
}
func ComplementHex(s string, x int) string {
	if len(s) == x {
		return s
	}
	if len(s) < x {
		for i := 0; i < x-len(s); i++ {
			s += "0"
		}
	}
	if len(s) > x {
		return s[:x]
	}
	return s
}
func Random() []byte {
	str := fmt.Sprintf("%x", newId())
	// strLow := ComplementHex(str[:(len(str)-1)/3], 8)
	strMid := ComplementHex(str[(len(str)-1)/3:(len(str)-1)*2/3], 4)
	<-time.After(1 * time.Nanosecond)
	ti := time.Now().UnixNano()
	return []byte(fmt.Sprintf("%x%s%s", ti, strMid, newId()))
}
func Sha1(b []byte) []byte {
	h := sha1.New()
	h.Write(b)
	return []byte(fmt.Sprintf("%x", h.Sum(nil)))
}
func newId() []byte {
	d := "abcdef012345689"
	da := make([]byte, 4)
	for i := 0; i < 4; i++ {
		<-time.After(time.Nanosecond * 10)
		da[i] = d[rand.New(rand.NewSource(time.Now().UnixNano())).Intn(15)]
	}
	return da
}
